#include "../../Command.h"

#include "../../User.h"

#include "../../NLogic/Static.h"
#include "../../NLogic/Equip.h"
#include "../../NLogic/SocialInfo.h"
#include "../../NResource/Static.h"

#include "../../Proxy.h"

namespace ProjectZ { namespace NCommand {

void sendPartyInviteUserCount(User * pUser, int count)
{
	//count++;

	if( count >= 3 )
	{
		count = 3;
	}
	else
	{
		count = 2;
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pAck << static_cast<uint8_t>(count);
	pAck->MakePacket(CMD_SC_PARTY_INVITE_USER_COUNT);
	pUser->Send(pAck);
}

void sendPartyCreateDoneFail(User *pUser)
{
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pAck << static_cast<int16_t>(-1) << static_cast<int8_t>(0);
	pAck->MakePacket(CMD_SN_PARTY_CREATE_DONE);
	pUser->Send(pAck);
}

void sendInvitePacket(User * pReceiver, User * pChief, int inviteecount)
{
	/*
	 * SC_PARTY_INVITE		0x1103
	{
		u8 u8party_membernum;	/// 파티구성원 수 2 or 3
		u32	party_seq;
		u16	costume_head;		// 코스튬정보(머리)
		u16	costume_body;		// 코스튬정보(갑옷)
		u16 costume_1st_weapon;	// 코스튬정보(무기)
		u16	costume_2nd_weapon;	// 코스튬정보(보조무기)
		u16	costume_effect;		// 코스튬정보(이펙트)
		u16	level;				// 레벨
		u8	class;
		u16	u16DungeonTID;		// 던전 TID
		u8	u8Difficult;		// 던전 난이도

		u32 u32gid;							/// 방장 GID
		str struser_id;						/// 카카오톡 사용자 아이디(GUID)  login ID 17자리
		str struser_nickname;				/// 카카오톡 사용자 닉네임.
		str struser_profile_image_url;		/// 카카오톡 프로필 이미지 URL
	}
	 */

	NLogic::Space * pSpace = pChief->GetSpace();
	NLogic::Equip * pEquip = pChief->GetEquip();
	if (NULL == pEquip)
	{
		DEBUGLOG("sendInvitePacket : pEquip is NULL!!");
		return;
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	if (pChief->GetCharacterInfo().avartar_iconidx == 1000)
	{
		pAck->MsgCat("%c%d%2d%2d%2d%2d%2d%2d%c%2d%c%d%s",
		inviteecount,
		pChief->GetSpace()->GetData()._index,
		pEquip->GetEquipItemIconIndex(ITEM_EQUIP_POS_HELMET),
		pEquip->GetEquipItemIconIndex(ITEM_EQUIP_POS_ARMOR),
		pEquip->GetEquipItemIconIndex(ITEM_EQUIP_POS_WEAPON),
		pEquip->GetEquipItemIconIndex(ITEM_EQUIP_POS_WEAPON),
		0,
		pChief->GetCharacterInfo().level,
		pChief->GetCharacterInfo().classtype,
		pSpace->GetData()._table_id,//pUser->player_info.DungeonInfo.map_tid,	// FIXME
		pSpace->GetData()._difficulty,	// FIXME
		pChief->GetUserSeq(),
		pChief->GetSocialID().c_str() );

		if( 1 == pChief->GetSocialInfo()->GetData()->_profile_opened )
			* pAck << pChief->GetUserInfo().nickname.c_str();
		else
			* pAck << static_cast<uint16_t>(0);

		* pAck << pChief->GetUserInfo().profile_url.c_str();
	}
	else
	{
		pAck->MsgCat("%c%d%2d%2d%2d%2d%2d%2d%c%2d%c%d%s",
		inviteecount,
		pChief->GetSpace()->GetData()._index,
		pChief->GetCharacterInfo().avartar_iconidx + 100,
		pChief->GetCharacterInfo().avartar_iconidx + 100,
		pChief->GetCharacterInfo().avartar_iconidx + 100,
		pChief->GetCharacterInfo().avartar_iconidx + 100,
		0,
		pChief->GetCharacterInfo().level,
		pChief->GetCharacterInfo().classtype,
		pSpace->GetData()._table_id,//pUser->player_info.DungeonInfo.map_tid,	// FIXME
		pSpace->GetData()._difficulty,	// FIXME
		pChief->GetUserSeq(),
		pChief->GetSocialID().c_str() );

		if( 1 == pChief->GetSocialInfo()->GetData()->_profile_opened )
			* pAck << pChief->GetUserInfo().nickname.c_str();
		else
			* pAck << static_cast<uint16_t>(0);

		* pAck << pChief->GetUserInfo().profile_url.c_str();
	}

	pAck->MakePacket(CMD_SC_PARTY_INVITE);
	pReceiver->Send(pAck);
}



void processSingleDungeon(User * pUser, ::Network::Packet * pPacket)
{
	int level = pUser->GetCharacterInfo().level;

	NResource::DungeonEnterLimitLevel * pDungeonEnterLimitLevel = NResource::Static::Instance().GetDungeonEnterLimitLevel();
	if (NULL == pDungeonEnterLimitLevel)
	{
		sendPartyCreateDoneFail(pUser);
		return;
	}

	uint16_t	u16table_id = 0;
	* pPacket >> u16table_id;

	int limitLevel = pDungeonEnterLimitLevel->GetLevel(u16table_id);
	if (level < limitLevel)
	{
		sendPartyCreateDoneFail(pUser);
		return;
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	pPacket->WriteBin(pPacket->GetPtr()+6, pPacket->GetEndLen()-6);
	pAck->MakePacket(CMD_SN_DUNGEON_DETAIL_INFO);
	pUser->Send(pAck, false);
}

void processPartyDungeon(User * pUser, ::Network::Packet * pPacket)
{
	NLogic::Party * pParty = pUser->GetParty();
	if (NULL == pParty)
	{
		DEBUGLOG("CN_DUNGEON_DETAIL_INFO processPartyDungeon NULL == pParty");
		return;
	}

	unsigned int level = pUser->GetCharacterInfo().level;
	NResource::DungeonEnterLimitLevel * pDungeonEnterLimitLevel = NResource::Static::Instance().GetDungeonEnterLimitLevel();
	if (NULL == pDungeonEnterLimitLevel)
	{
		sendPartyCreateDoneFail(pUser);
		return;
	}

	uint16_t	u16table_id = 0;
	* pPacket >> u16table_id;

	unsigned int limitLevel = pDungeonEnterLimitLevel->GetLevel(u16table_id);
	if (level < limitLevel)
	{
		sendPartyCreateDoneFail(pUser);
		return;
	}

	pUser->GetSpace()->SetDetailInfoPacket(pPacket);
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	pAck->WriteBin(pPacket->GetPtr()+6, pPacket->GetEndLen()-6);
	pAck->MakePacket(CMD_SN_DUNGEON_DETAIL_INFO);
	pUser->Send(pAck);

	if (pUser->GetEnumState() == User::EnumState::FRIEND_PARTY_WAIT)
	{
		int sendCount = 0;
		bool bLevelCap = false;

		auto tree = pUser->GetParty()->GetInviteUserTree();
		auto itr = tree.begin();
		for (; itr != tree.end(); ++itr)
		{
			User * pFriend = itr->second;

			if (NULL == pFriend->GetSpace())
				continue;

			if (pFriend->GetEnumState() != User::EnumState::INVITE)
				continue;

			if (pFriend->GetCharacterInfo().level < limitLevel)
			{
				bLevelCap = true;
				break;
			}

			sendCount++;
		}

//		std::for_each(pUser->GetParty()->GetInviteUserTree().begin(), pUser->GetParty()->GetInviteUserTree().end(), [&](const std::pair<int, User * > & pair) {
//
//			if (NULL != pair.second->GetSpace() && pair.second->GetEnumState() == User::EnumState::INVITE)
//			{
//				sendInvitePacket(pair.second, pUser, pUser->GetParty()->GetInviteUserTree().size() + 1);
//				pair.second->SetEnumState(User::EnumState::ACCEPT_WAIT);
//				sendCount++;
//			}
//
//		} );

		if (sendCount <= 0 || true == bLevelCap)
		{
			pUser->GetSpace()->LeaveUser(pUser);
			pUser->SetEnumState(User::EnumState::__NONE__);
			pUser->_getWorldSpace()->EnterUser(pUser);

			sendPartyCreateDoneFail(pUser);

			return;
		}

		std::for_each(pUser->GetParty()->GetInviteUserTree().begin(), pUser->GetParty()->GetInviteUserTree().end(), [&](const std::pair<int, User * > & pair) {
			sendInvitePacket(pair.second, pUser, pUser->GetParty()->GetInviteUserTree().size() + 1);
			pair.second->SetEnumState(User::EnumState::ACCEPT_WAIT);
		} );

		sendCount += 1;

		sendPartyInviteUserCount(pUser, sendCount);
		pUser->GetParty()->AddAcceptUserTree(pUser);
		pUser->GetParty()->SetState(NLogic::Party::State::ACCEPT_WAIT);
	}
	else if (pUser->GetEnumState() == User::EnumState::RANDOM_PARTY_WAIT)
	{
#if 0
		int sendCount = 0;
		auto itr = NProxy::GetUserTree().begin();
		for (;itr != NProxy::GetUserTree().end(); ++itr)
		{
			User * pTarget = itr->second;
			if (NULL == pTarget)
				continue;

			NLogic::Space * pSpaceTemp = pTarget->GetSpace();
			if (NULL == pSpaceTemp)
			{
				continue;
			}

			if (pTarget->GetEnumState() != User::EnumState::__NONE__)
				continue;

			NLogic::SocialInfo * pSocialInfo = pTarget->GetSocialInfo();
			if (NULL == pSocialInfo)
				continue;

			NLogic::SocialInfo::Data * pData = pSocialInfo->GetData();
			if (NULL == pData)
				continue;

			if (0 == (pData->_invite_blocked & static_cast<int>(NLogic::SocialInfo::EnumInviteState::DUNGEON_ON)))
				continue;

			sendCount++;

			if (sendCount >= MAX_PARTY_DUNGEON_INVITE)
				break;
		}

		if (sendCount <= 0)
		{
			pUser->GetSpace()->LeaveUser(pUser);
			pUser->SetEnumState(User::EnumState::__NONE__);
			pUser->_getWorldSpace()->EnterUser(pUser);
			sendPartyCreateDoneFail(pUser);

			return;
		}

		sendCount += 1;

		int done = 0;
		int userCount = NProxy::GetUserTree().size();
		if (userCount <= 10)
		{
			//int seed = rand() % 2 + 1;
			auto itr = NProxy::GetUserTree().begin();
			for (;itr != NProxy::GetUserTree().end(); ++itr)
			{
				User * pTarget = itr->second;
				if (NULL == pTarget)
					continue;

				NLogic::Space * pSpaceTemp = pTarget->GetSpace();
				if (NULL == pSpaceTemp)
				{
					continue;
				}

				if (pTarget->GetEnumState() != User::EnumState::__NONE__)
					continue;

				NLogic::SocialInfo * pSocialInfo = pTarget->GetSocialInfo();
				if (NULL == pSocialInfo)
					continue;

				NLogic::SocialInfo::Data * pData = pSocialInfo->GetData();
				if (NULL == pData)
					continue;

				if (0 == (pData->_invite_blocked & static_cast<int>(NLogic::SocialInfo::EnumInviteState::DUNGEON_ON)))
					continue;

				if (false == pTarget->EndBattle_afterEffect())
					continue;

//				if (0 != pTarget->GetUserSeq() % seed)
//					continue;

				sendInvitePacket(itr->second, pUser, sendCount);
				pUser->GetParty()->EnterUser(pTarget);
				pUser->GetParty()->AddInviteUserTree(pTarget);
				pTarget->SetEnumState(User::EnumState::ACCEPT_WAIT);
				pTarget->SetParty(pUser->GetParty());

				done++;

				if (done >= MAX_PARTY_DUNGEON_INVITE)
					break;
			}
		}
		else if (10 < userCount && userCount <= 50)
		{
			int seed = rand() % 3 + 1;
			auto itr = NProxy::GetUserTree().begin();
			for (;itr != NProxy::GetUserTree().end(); ++itr)
			{
				User * pTarget = itr->second;
				if (NULL == pTarget)
					continue;

				NLogic::Space * pSpaceTemp = pTarget->GetSpace();
				if (NULL == pSpaceTemp)
				{
					continue;
				}

				if (pTarget->GetEnumState() != User::EnumState::__NONE__)
					continue;

				NLogic::SocialInfo * pSocialInfo = pTarget->GetSocialInfo();
				if (NULL == pSocialInfo)
					continue;

				NLogic::SocialInfo::Data * pData = pSocialInfo->GetData();
				if (NULL == pData)
					continue;

				if (0 == (pData->_invite_blocked & static_cast<int>(NLogic::SocialInfo::EnumInviteState::DUNGEON_ON)))
					continue;

				if (0 != pTarget->GetUserSeq() % seed)
					continue;

				if (false == pTarget->EndBattle_afterEffect())
					continue;

				sendInvitePacket(itr->second, pUser, sendCount);
				pUser->GetParty()->EnterUser(pTarget);
				pUser->GetParty()->AddInviteUserTree(pTarget);
				pTarget->SetEnumState(User::EnumState::ACCEPT_WAIT);
				pTarget->SetParty(pUser->GetParty());
				done++;

				if (done >= MAX_PARTY_DUNGEON_INVITE)
					break;
			}
		}
		else if (50 < userCount && userCount <= 500)
		{
			int seed = rand() % 9 + 1;
			auto itr = NProxy::GetUserTree().begin();
			for (;itr != NProxy::GetUserTree().end(); ++itr)
			{
				User * pTarget = itr->second;
				if (NULL == pTarget)
					continue;

				NLogic::Space * pSpaceTemp = pTarget->GetSpace();
				if (NULL == pSpaceTemp)
				{
					continue;
				}

				if (pTarget->GetEnumState() != User::EnumState::__NONE__)
					continue;

				NLogic::SocialInfo * pSocialInfo = pTarget->GetSocialInfo();
				if (NULL == pSocialInfo)
					continue;

				NLogic::SocialInfo::Data * pData = pSocialInfo->GetData();
				if (NULL == pData)
					continue;

				if (0 == (pData->_invite_blocked & static_cast<int>(NLogic::SocialInfo::EnumInviteState::DUNGEON_ON)))
					continue;

				if (0 != pTarget->GetUserSeq() % seed)
					continue;

				if (false == pTarget->EndBattle_afterEffect())
					continue;

				sendInvitePacket(itr->second, pUser, sendCount);
				pUser->GetParty()->EnterUser(pTarget);
				pUser->GetParty()->AddInviteUserTree(pTarget);
				pTarget->SetEnumState(User::EnumState::ACCEPT_WAIT);
				pTarget->SetParty(pUser->GetParty());
				done++;

				if (done >= MAX_PARTY_DUNGEON_INVITE)
					break;
			}
		}
		else
		{
			auto itr = NProxy::GetUserTree().begin();
			for (;itr != NProxy::GetUserTree().end(); ++itr)
			{
				User * pTarget = itr->second;
				if (NULL == pTarget)
					continue;

				NLogic::Space * pSpaceTemp = pTarget->GetSpace();
				if (NULL == pSpaceTemp)
				{
					continue;
				}

				if (pTarget->GetEnumState() != User::EnumState::__NONE__)
					continue;

				NLogic::SocialInfo * pSocialInfo = pTarget->GetSocialInfo();
				if (NULL == pSocialInfo)
					continue;

				NLogic::SocialInfo::Data * pData = pSocialInfo->GetData();
				if (NULL == pData)
					continue;

				if (0 == (pData->_invite_blocked & static_cast<int>(NLogic::SocialInfo::EnumInviteState::DUNGEON_ON)))
					continue;

				if (false == pTarget->EndBattle_afterEffect())
					continue;

				sendInvitePacket(itr->second, pUser, sendCount);
				pUser->GetParty()->EnterUser(pTarget);
				pUser->GetParty()->AddInviteUserTree(pTarget);
				pTarget->SetEnumState(User::EnumState::ACCEPT_WAIT);
				pTarget->SetParty(pUser->GetParty());
				done++;

				if (done >= MAX_PARTY_DUNGEON_INVITE)
					break;
			}
		}

		sendPartyInviteUserCount(pUser, done);
		pUser->GetParty()->SetState(NLogic::Party::State::ACCEPT_WAIT);
		pUser->GetParty()->AddAcceptUserTree(pUser);
#endif
	}
	else
	{
		sendPartyCreateDoneFail(pUser);
	}
}

void processNewPartyRoom(User * pUser, ::Network::Packet * pPacket)
{
	NLogic::Party * pParty = pUser->GetParty();
	if (NULL == pParty)
	{
		DEBUGLOG("%s NULL == pParty", __FUNCTION__);
		return;
	}

	NLogic::Space * pSpace = pUser->GetSpace();
	if (NULL == pSpace)
	{
		DEBUGLOG("%s NULL == pSpace", __FUNCTION__);
		return;
	}

	pSpace->SetDetailInfoPacket(pPacket);
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	pAck->WriteBin(pPacket->GetPtr()+6, pPacket->GetEndLen()-6);
	pAck->MakePacket(CMD_SN_DUNGEON_DETAIL_INFO);
	pUser->Send(pAck);


	// Party Timer 가동....

	pParty->SetState(NLogic::Party::State::NEW_PARTY_ROOM_WAIT);

}

void
Command::CN_DUNGEON_DETAIL_INFO(User * pUser, ::Network::Packet * pPacket)
{
	/*
	 * ///방장이 던전 세팅 정보 서버에 전송  C->S
		CN_DUNGEON_DETAIL_INFO			0x0803
		{
			u16	u16table_id;
			u8 u8difficult				/// 난이도
			u8 u8pos_x;					///	세팅될 맵 X
			u8 u8pos_y;					///	세팅될 맵 Y
			u16 u16start_map_seq;		/// 시작맵 시퀀스
			u16	u16end_map_seq;			///	종료맵시퀀스

			u16	u16count;				///	반복횟수
			{
				s8 s8upper_road_active;	/// 상측 길 활성여부
				s8 s8right_road_active; ///	우측 길 활성여부
				s8 s8lower_road_active;	///	하측 길 활성여부
				s8 s8left_road_active;	///	좌측 길 활성여부
				s8 s8set_depth;			///	세팅뎁스
				u16 u16mob_lv1;			///	몬스터1 LV
				u16 u16mob_tid1;		///	몬스터1 TID
				u16 u16mob_lv2;			///	몬스터2 LV
				u16 u16mob_tid2;		///	몬스터2 TID
				u16 u16mob_lv3;			///	몬스터3 LV
				u16	u16mob_tid3;		/// 몬스터3 TID
				u16 u16map_id;			///	맵번호
				u8	u8legend_apppear;	/// 레전드 출현여부
			}
		}

		/// 방장이 보낸 던전 세부 정보 클라이언트에 전송(방장포함)  S->C
		SN_DUNGEON_DETAIL_INFO			0x0804
		{
			u16	u16table_id;
			u8 u8difficult				/// 난이도
			u8 u8pos_x;					///	세팅될 맵 X
			u8 u8pos_y;					///	세팅될 맵 Y
			u16 u16start_map_seq;		/// 시작맵 시퀀스
			u16	u16end_map_seq;			///	종료맵시퀀스

			u16	u16count;				///	반복횟수
			{
				s8 s8upper_road_active;	/// 상측 길 활성여부
				s8 s8right_road_active; ///	우측 길 활성여부
				s8 s8lower_road_active;	///	하측 길 활성여부
				s8 s8left_road_active;	///	좌측 길 활성여부
				s8 s8set_depth;			///	세팅뎁스
				u16 u16mob_lv1;			///	몬스터1 LV
				u16 u16mob_tid1;		///	몬스터1 TID
				u16 u16mob_lv2;			///	몬스터2 LV
				u16 u16mob_tid2;		///	몬스터2 TID
				u16 u16mob_lv3;			///	몬스터3 LV
				u16	u16mob_tid3;		/// 몬스터3 TID
				u16 u16map_id;			///	맵번호
				u8	u8legend_apppear;	/// 레전드 출현여부
			}
		}

	 */
	PREPARE_PACKET;

	NLogic::Space * pSpace = pUser->GetSpace();
	if (NULL == pSpace)
	{
		DEBUGLOG("CN_DUNGEON_DETAIL_INFO NULL == pSpace");
		return;
	}

	if (NULL == pSpace->GetMaster())
	{
		DEBUGLOG("CN_DUNGEON_DETAIL_INFO NULL == pSpace->GetMaster()");
		return;
	}

	if (pSpace->GetMaster()->GetUserSeq() != pUser->GetUserSeq())
	{
		DEBUGLOG("CN_DUNGEON_DETAIL_INFO user is not master");
		return;
	}

	if (false == pSpace->IsDungeon())
	{
		DEBUGLOG("CN_DUNGEON_DETAIL_INFO space is not single or party dungeion");
		return;
	}

	if (pSpace->GetData()._spaceType == NLogic::Space::SpaceType::SINGLE_DUNGEION)
	{
		processSingleDungeon(pUser, pPacket);
		return;
	}

	if (pSpace->GetData()._spaceType == NLogic::Space::SpaceType::PARTY_DUNGEION)
	{
		processPartyDungeon(pUser, pPacket);
		return;
	}

	if (pSpace->GetData()._spaceType == NLogic::Space::SpaceType::NEW_PARTY_ROOM)
	{
		processNewPartyRoom(pUser, pPacket);
		return;
	}
}


} /*NCommand*/ } /*ProjectZ*/



